///////////////////////////////////////////////////////////////
//  Copyright Christopher Kormanyos 2002 - 2011.
//  Copyright 2011 John Maddock. Distributed under the Boost
//  Software License, Version 1.0. (See accompanying file
//  LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
//
// This work is based on an earlier work:
// "Algorithm 910: A Portable C++ Multiple-Precision System for Special-Function Calculations",
// in ACM TOMS, {VOL 37, ISSUE 4, (February 2011)} (C) ACM, 2011. http://doi.acm.org/10.1145/1916461.1916469

#ifdef _MSC_VER
#define _SCL_SECURE_NO_WARNINGS
#endif

#include <boost/detail/lightweight_test.hpp>
#include <boost/array.hpp>
#include "test.hpp"

#if !defined(TEST_MPF_50) && !defined(TEST_MPF) && !defined(TEST_BACKEND) && !defined(TEST_CPP_DEC_FLOAT) && \
    !defined(TEST_MPFR) && !defined(TEST_MPFR_50) && !defined(TEST_MPFI_50) && !defined(TEST_FLOAT128) &&    \
    !defined(TEST_CPP_BIN_FLOAT)
#define TEST_MPF_50
//#  define TEST_MPF
#define TEST_BACKEND
#define TEST_CPP_DEC_FLOAT
#define TEST_MPFI_50
#define TEST_FLOAT128
#define TEST_CPP_BIN_FLOAT

#ifdef _MSC_VER
#pragma message("CAUTION!!: No backend type specified so testing everything.... this will take some time!!")
#endif
#ifdef __GNUC__
#pragma warning "CAUTION!!: No backend type specified so testing everything.... this will take some time!!"
#endif

#endif

#if defined(TEST_MPF_50)
#include <nil/crypto3/multiprecision/gmp.hpp>
#endif
#if defined(TEST_MPFR_50)
#include <nil/crypto3/multiprecision/mpfr.hpp>
#endif
#if defined(TEST_MPFI_50)
#include <nil/crypto3/multiprecision/mpfi.hpp>
#endif
#ifdef TEST_BACKEND
#include <nil/crypto3/multiprecision/concepts/mp_number_archetypes.hpp>
#endif
#ifdef TEST_CPP_DEC_FLOAT
#include <nil/crypto3/multiprecision/cpp_dec_float.hpp>
#endif
#ifdef TEST_FLOAT128
#include <nil/crypto3/multiprecision/float128.hpp>
#endif
#ifdef TEST_CPP_BIN_FLOAT
#include <nil/crypto3/multiprecision/cpp_bin_float.hpp>
#endif

template<class T>
struct has_poor_large_value_support {
    static const bool value = false;
};
#ifdef TEST_CPP_DEC_FLOAT
template<unsigned Digits10, class ExponentType, class Allocator,
         nil::crypto3::multiprecision::expression_template_option ExpressionTemplates>
struct has_poor_large_value_support<nil::crypto3::multiprecision::number<
    nil::crypto3::multiprecision::cpp_dec_float<Digits10, ExponentType, Allocator>, ExpressionTemplates>> {
    static const bool value = true;
};
#endif
#ifdef TEST_CPP_BIN_FLOAT
template<unsigned Digits, nil::crypto3::multiprecision::backends::digit_base_type DigitBase, class Allocator,
         class Exponent, Exponent MinE, Exponent MaxE,
         nil::crypto3::multiprecision::expression_template_option ExpressionTemplates>
struct has_poor_large_value_support<nil::crypto3::multiprecision::number<
    nil::crypto3::multiprecision::cpp_bin_float<Digits, DigitBase, Allocator, Exponent, MinE, MaxE>,
    ExpressionTemplates>> {
    static const bool value = true;
};
#endif

template<class T>
void test() {
    std::cout << "Testing type " << typeid(T).name() << std::endl;
    static const boost::array<const char*, 101u> data = {{
        "-2."
        "37609908807915949996042688873953402912174184373388399043229539427530802169622688886435380890546981798452174137"
        "747437590e-1",
        "8."
        "03406366226813589517543567844755380935198206635917017883860879215939165740799963435747185200486086864198723786"
        "516760875e-1",
        "8."
        "60219386510802105228997694366289682807721120146423711696179175800635220710279361583231346318224971127450760223"
        "168489952e-1",
        "-1."
        "36768951513839774357595871594675554406872039078811749027554673949684004409484639336417431285061889554892096426"
        "752261915e-1",
        "-9."
        "66210139195431691033548069227792927999642647449593184440815029076272297050360196975341458076547426373476590671"
        "462150981e-1",
        "-6."
        "12007278553856790723803948280976098970972124581361775428331444376106018942231526074915731012122426588769327127"
        "413045994e-1",
        "4."
        "91927698740873688392439262912409276430264703350691359723802294639643655296838880236042651349290074585311025856"
        "549893171e-1",
        "9."
        "93232596718899824059271235487971663771012607519717340071654721877802691370866768064059943491135925674950430467"
        "047724563e-1",
        "2."
        "77789911520199551017947550534057049374212876971194676010301098598339529915403722848373365985645657342475739669"
        "568931563e-1",
        "-7."
        "77955945956221239101360662190442739163791527953499629555756394261998892874934847131138921705713935365505245406"
        "994428077e-1",
        "-8."
        "80676278306736581575818642341143682410874043182925227659938804267878718513212454821032629378618345485453587099"
        "696563832e-1",
        "9."
        "54652155963865007116798560589970996367213754762169439269792747771200843006278637115722685610960738675814993576"
        "019945344e-2",
        "9."
        "54658201427917718824191302196929158303422390793460018465335986921801519149657723689322277773550748806000948225"
        "466432438e-1",
        "6."
        "44358700620889799575033272322899136331490664925359198096632560532437137894857803619177106562399406351419810452"
        "110265174e-1",
        "-4."
        "55304635273050571206400777159475409897339683148730716647371922365967582339285347105376503917296765204188604297"
        "021364549e-1",
        "-9."
        "97202532932553753622481171186283382950122646390227670693679248197349800205205290898290539070732778341271049474"
        "946533154e-1",
        "-3."
        "17489525058325500707686194437148362752290391406825231198381521862930317513649081353670386166519524315810546189"
        "268634469e-1",
        "7."
        "51160186640147504067744846462384089742696250681200524524912647858645140367792164416711871535116761744380912486"
        "921554617e-1",
        "8."
        "99610194168373157174515848193119670768490559799348397680196213249921436405001710937402190319584272526657508442"
        "591319630e-1",
        "-5."
        "39963892484342940823660554048696208293700871414984387094529796385334086703752106515008832585578915389731907422"
        "242902573e-2",
        "-9."
        "41455348900839346761557896365239742769987576963330061702397697388879776230596944312519157729410022380228287314"
        "835345969e-1",
        "-6."
        "75595816763857390859268297670835380459024839344154743310231115864242050771191159334664874097564054770066166961"
        "642073448e-1",
        "4."
        "17894201894880415042381733708896725748531223743344790054523182948440843948904650988733732381978194392219295696"
        "279423635e-1",
        "9."
        "99447981389824371458566861195586395552622718284098766856978062347139060489410032781030191080200904443096549587"
        "568037683e-1",
        "3."
        "56640095868759075150409032448421838265699043643228482503057299699740924345262819242042067863780263400092250418"
        "388628640e-1",
        "-7."
        "23065426868134142613141384486526262450487633432466529798821958977732347646832059032382447792655111641456570392"
        "189752211e-1",
        "-9."
        "16988391192434436877664999042786024703848714036221388727578305299843547352325574309860356272561772723624753484"
        "063972217e-1",
        "1."
        "24341855683226931265962750806821531283439413068694552738675989282017066737438591268502070364982899342633928417"
        "210588531e-2",
        "9."
        "26624413643579136646620112107410908114766812511471130116341925013001661546817531064974089666536893346764523464"
        "250445838e-1",
        "7."
        "05664607841658050248613256866289182754229289446384595719719495272020558391145537620968819401219414243210529013"
        "148958366e-1",
        "-3."
        "79761093422301890838671114556341706055562482358183402807224298533060188038450560241345615647754569347252101282"
        "386222173e-1",
        "-9."
        "99965058979463689113370264378210962384824970050865061898892508056811665771886385589295806419278045318841717598"
        "003331419e-1",
        "-3."
        "95173919871548266286836251448043149039940610894391718791244019288314418437411707835924620250473697245151743147"
        "215758686e-1",
        "6."
        "93720251624319621941983929806434090162802383400620564454074825718151625795576680427510026452063593762417421561"
        "201654156e-1",
        "9."
        "32780816819880202610269817418700102084277332259524791943833699964920012022753227823298655560837271746316929623"
        "378078695e-1",
        "2."
        "91495208658083070508005579692813621670878962971611104453227900103973434149303469066898102622556226584993895360"
        "896300290e-2",
        "-9."
        "10191043170480685360743788297835112117551819731152897291272407935139876953384666161532187572493791297095784055"
        "525159185e-1",
        "-7."
        "34513075127503122343910106816656237074878218180284276449954797048122379869002663646507706411949095015624141821"
        "039453971e-1",
        "3."
        "40971254411713599427147477626159847871020791931107106418841144080445813896332252160005593096670674809345703079"
        "384115052e-1",
        "9."
        "98752871506016936810666998588493462933191829230756181478046320353377054175122206889047094521687205093218701141"
        "334147081e-1",
        "4."
        "33024359542714849537532946954507232835434973891665238942502273464321666207117525270650546741831354943253652514"
        "490075246e-1",
        "-6."
        "63175408268187738636594884921931867786416057472876635147295424128144233911929585327601381618059327766986981109"
        "409782838e-1",
        "-9."
        "46960160806563725719808910991708075372282242401645009270517113290439792088443109178772446465191984149998211903"
        "724560065e-1",
        "-7."
        "06828182905581345108929510344440443421290640066613022421187316650733628538705972455891575947230299102119854983"
        "197703150e-2",
        "8."
        "92183656127948379886438402777950080111433733329436790239129260607557296960582455582584117031260710927499215646"
        "838011844e-1",
        "7."
        "62091330231640362984555508176991632755732840163230620595759320390970951235395195394649584713540498911356433919"
        "369698423e-1",
        "-3."
        "01591765120371930643555588643712101466544136366607065361801475091335195383846047491935017919396438040414024941"
        "341524187e-1",
        "-9."
        "95813515236177554177387795413035497724212540625760091518605741283184405719984044075159457509720410668598540884"
        "613985023e-1",
        "-4."
        "70125959152223022135690700550251564040118601846181392455764893020377582359429013073566263451488554529709131439"
        "092909247e-1",
        "6."
        "31483718775865440843182928017874708719203714677143270278178885379757350754752477512514449375355491054871712891"
        "789652146e-1",
        "1."
        "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
        "000000000",
        "3."
        "87481045630097871028201331640164477694000480353342897357083794605539506785023570062767753819472037935010414476"
        "627195076e-1",
        "-6."
        "99716878554812023132822640034166338740077082416915046841339368979161296335086955803240899441098534898926193252"
        "558848693e-1",
        "-9."
        "29735101124991407032113033015438177585645722877060262785796302722011806301680288369763295777635760805579255008"
        "366302180e-1",
        "-2."
        "07925797310208845709174899248298159909010721767168338004516304026594885686024530923209628704670627250569637267"
        "490913462e-2",
        "9."
        "13621640053945104047985280883096238900189007462190433514805702721127019097915088259906184736442916334750420359"
        "005079959e-1",
        "7."
        "28814716527795995795780587639833705107995825167970668466246348938821997240383021826681253777014938636567626203"
        "524137506e-1",
        "-3."
        "48817863192357573536083313907744269588018702862402502601699983054718835012048372083235768555953613790431700360"
        "695537918e-1",
        "-9."
        "99135337256258278958854200595331742602280601557283993231562055717063052179292021052372510863057206152466386086"
        "657442382e-1",
        "-4."
        "25474147219713305654097901385832164424798803616095278869643928816776198489330071073326518019520590535564717523"
        "756486665e-1",
        "6."
        "69409002349720857726983952566596052122726437391092096671257338244059819036586172017092390651026654050631669646"
        "310910927e-1",
        "9."
        "44240747589054266930136705015787520728797286842746645573763175559132491628984502333043316023599487896169049499"
        "868916865e-1",
        "6."
        "23417820549832676844933182722733277887833220127638406914080428946880981800946578131712749910941183940944526141"
        "109771339e-2",
        "-8."
        "95928229794837090592434136137683839101829890460754766346170956577979909285084363961363023377587044303560652568"
        "203578379e-1",
        "-7."
        "56652196635835430995109388017590459596111729342964992503572530290981857981790620732129221157071082788019187787"
        "999930361e-1",
        "3."
        "09551461133309219674309651201007026752336319933918953736299690287371505733386433918863300129026763968979930342"
        "098019300e-1",
        "9."
        "96542844308353945757715814452637400116215448012622700698887257177706625278927018059066920597035660000571997275"
        "705962011e-1",
        "4."
        "62731465522276407764000677957978862104808823938378826581864482071733508960062598574638347814740748458034065235"
        "894523010e-1",
        "-6."
        "37943500095315456672541800050589670140910744260281868746767523730582697622604545933849801882909439609368258115"
        "114388202e-1",
        "-9."
        "57113494461990955768932962010819183910065445494138937651443249061391692258872250121438832853873660881630205561"
        "168895590e-1",
        "-1."
        "03783175146302830356973378710923690121182237844646430783773333188328606275124873219756415071202025673009660963"
        "930966273e-1",
        "8."
        "76685468012988943166112725030293740012198666616661362437433807594683780986916439696374569274720383546275206733"
        "493672834e-1",
        "7."
        "83181178815072182812568575402104911406191663934571600092749188502783771503475038116599065276589122015600004250"
        "624262132e-1",
        "-2."
        "69749743842835294071354429049113807280228918034124159074991560056663623624511602063409428877143567459307323934"
        "051784210e-1",
        "-9."
        "92227004420417932443416371636723983768124774541445787394585828303853075015733744933294181104002649816119116502"
        "663362907e-1",
        "-4."
        "99188570507651271652464431008309802023236218596632956064119419694573621896525872847587264755853127438644874992"
        "889777436e-1",
        "6."
        "05374785886620830935500306718810628353011877048386199574451402773468315797082901705593423724389976967865835641"
        "164117478e-1",
        "9."
        "68331080574540181354402420018944004334504868848934676984951546671476956051983469715128604348963016773169794077"
        "158289730e-1",
        "1."
        "45045093347669933436797325432376656017480150281100519869038554695618054318368975927557872948037203212941966706"
        "926758604e-1",
        "-8."
        "55926631706799584065153976496431313099942493164544290051315786450857575707615522517293656706329757352795226750"
        "189755758e-1",
        "-8."
        "08355785820466703104647317116964786017731181599256098405978700298563758509572188640629418770593008092680980412"
        "866065299e-1",
        "2."
        "29481541445091823694157468006983283649885473964756916206813927875661041834620526229807744443043682778028709792"
        "615798955e-1",
        "9."
        "86195281084368344446227722442335005500018635181693920385626820970119467136148305491035657795704047666385553672"
        "680209923e-1",
        "5."
        "34782415974986828906369231191245075731384342252264783019973387059318216570499447505623911253042567598873910043"
        "381675873e-1",
        "-5."
        "71759181631212640256161075896307515511612057247572886814941945052483422285718810088660759708176904381865453799"
        "197101481e-1",
        "-9."
        "77874107069129472007009478090869879295520839405452365411822873037906082086100232576241983901051327761231156641"
        "104065497e-1",
        "-1."
        "86056181372276495846711248156316208757691570931906856005697361080864028851991674077024223201008430626166447144"
        "444086146e-1",
        "8."
        "33687619660983803179149188531271900120055171980951416163724579833511897001564116810390933587615557717585362295"
        "882429826e-1",
        "8."
        "32132482562487183916482822112362004641509381783438374175226355792137053285527706239574867923387554339582561002"
        "247202518e-1",
        "-1."
        "88816490768820368180947188938258919466912959009058295775702554895970560887437777994365295452696990115940651570"
        "073217522e-1",
        "-9."
        "78458105113103660973458641126689066610890753079836635611789969774219913050456840122278188955139015473252491612"
        "410972950e-1",
        "-5."
        "69451448580118869157805059117807250106203230622762838051154208713065707949727035884250775206017528612930773233"
        "017928006e-1",
        "5."
        "37154819650306918873973169624898539483418364490295996462663218848771864764982600193558748568095521886456306061"
        "269765631e-1",
        "9."
        "85726070946814004698231423834505649751779161578718404221294527194525251740198034173542003704080544827976936213"
        "857653517e-1",
        "2."
        "26745517700332138489400566746499809209783385009289423848083137846668382711005704387134606000570923556980021574"
        "851618566e-1",
        "-8."
        "10006890365888881023982873786181048364505748637138923322482323010218991062084191379116946709356002103893071903"
        "481540337e-1",
        "-8."
        "54470151393449484710948210543666267680196067632693416660536443330720708402601669617638569732848938319544250428"
        "600991723e-1",
        "1."
        "47824914922605209542648603104533928946885824995208478684499907657728115943168395067575842431291755277452367320"
        "596435067e-1",
        "9."
        "69028856602232134498324179654622883463820270279077886397861028881882684131282848087869087883519707948141915733"
        "221980948e-1",
        "6."
        "03135714281336943093251136556365407562473924416812270469171432809743173719168209727199952532489544254928975940"
        "518615351e-1",
        "-5."
        "01621542149055350065079347615664213658089623368745676779267390227688581807037821041573344917735076902116221444"
        "127518632e-1",
    }};

    boost::uintmax_t max_err = 0;
    for (unsigned k = 0; k < data.size(); k++) {
        static const T euler_gamma = static_cast<T>(
            "5."
            "7721566490153286060651209008240243104215933593992359880576723488486772677766467093694706329174674951463144"
            "7249807082480960504014486542836224173997644923536253500333742937337737673942792595258247094916008735203948"
            "165670853233151776611528621199501507984793745085705740029921354786146694029604325421519e-1");
        T val = cos(euler_gamma * ((100 * k) - 5000));
        T e = relative_error(val, T(data[k]));
        unsigned err = e.template convert_to<unsigned>();
        if (err > max_err)
            max_err = err;
        val = cos(-euler_gamma * ((100 * k) - 5000));
        e = relative_error(val, T(data[k]));
        err = e.template convert_to<unsigned>();
        if (err > max_err)
            max_err = err;
    }
    std::cout << "Max error was: " << max_err << std::endl;
    BOOST_TEST(max_err < 5000000000ULL);

    static const boost::array<const char*, 51u> near_one = {{
        "0."
        "00110366261514314701760139373423242154915684721997331411894924799093985950797185797611128868398841547825787890"
        "29173541058712364395631700458578107381027292873036746420205387223485877413957850165491398541686055903366332748"
        "90874911975139498047488076101124170425114828336211817830671418321600962996502656221412102902998671173649312277"
        "667706874059520046508702908872747388744526457997404065469953155187340837",
        "0."
        "00301570415724321900197177647763221470492248879133312120541736694616735167707691487355585402909157545142690977"
        "99280330158745508542936966046640795712691698490758472574837678659161855207596563250546269614348515005196657786"
        "35964602053723130112149272857741021255035007050242648280249045257241587921499420186440290159530972645802667288"
        "8041860289772080407882673424767232857435141510615538430445535588448032261",
        "0."
        "00492773467417506941191096162314029013605001850224827873626164128562333386792088309741247498307937783239976846"
        "40684587346403570647040211088376986993615001420565608501262335822815041623056442245053684626079448221530207757"
        "67293904803094516494852132040157407480296626097590447877531473000279989504965298305212515143651158933512325458"
        "2883803928373794668948878049089088843407672795237410750365571990834236348",
        "0."
        "00683974717571121080445443392813999685632538584115280163639002456100681615640914993980241106350898662127895834"
        "03491711476788985949178019078796740862827299289838108117219486357027460681238178010067475221327133396780718266"
        "88054027293686018578397693756990377816017022516632892020169982747289382436383843962743718776515977026228293029"
        "3057633886299749088561182830982345936603553661004526800797082995898813903",
        "0."
        "00875173467169001855272097602878830498126325132779978740284784353109833803345638909895616095616059746086966621"
        "15691834835879797726785572307430505839752709777545184759704897411565241193788473054468453310985269625798043619"
        "60647344836744631465315238254178161716870409320747176674142306881908614436607977326507761331050644035013756409"
        "444911127742401762647885817361924274132830920030936589562922803846509607",
        "0."
        "01066369017204128630619294878289599088122703310476300562904756326253141837346523787668052900505853398101079375"
        "94469668686284809087098124021790477748880947611042381318432390371672122064698944855990857172168556376203187234"
        "57013401360290343196462723174177342294339229792213396006286331141933952648238459364417067676760977202812721209"
        "681621184724443514062993874571816382775241753902032787099435678672474841",
        "0."
        "01257560668681178111677881586444664374671816674492792378513923371024001720173762508840686118578173962829321343"
        "63233143767089335349337484367207215684622673170266885614381441138552901409251204353175061698564613866238289415"
        "31577425811393721991195661429557079268566156800689149725770186985872449679872155877537432897653904213375816262"
        "709009448220490217917537801655330411526526290708967440087145630462068976",
        "0."
        "01448747722619079813723045783566494487281080221130834268505563740030547402155202849377855910255202538088047710"
        "30651876883379317135405575623739914318802515536209478369407265445536477399941573009672629419769333751159466292"
        "04615918888689039777423610894099269527633757403818072000860056651445780074486612843419789636984117740884711882"
        "675016016919064788076097669389652323393864660933705259163296837955978748",
        "0."
        "01639929480053571479848938435852490010528683615442189056243891786250141194724503798645591969636530166611241489"
        "00972464797621494569628096385882454669885840933802635455430234110872033519486815599053360100669006671017871388"
        "62856447778428938265451537422367650992162004154495705878092019403922006152498705687706013973674800621422751806"
        "347308220226407830977673540994341535381202679482907460136241543505771361",
        "0."
        "01831105242039754437253785820100114508391422302962227147815985292569212444264024710033626204144036041239231890"
        "25582951084525131234541035045166074987638637282847972029789754092641411388617381844682575761572045523836754427"
        "80049333490201800526935793000727771598103735596829143729912656158790924063286176336412427525710457367751437348"
        "230246446466833498557166002214984255422115833828533909144072330080184872",
        "0."
        "02022274309654648882733319123724659176063973070470414879500960262717528101345886555723824083020397369049288293"
        "55531115197594748355566868125534301344427130576222743485105269313331244379284820013012147761113588480261646884"
        "47150395879262705323533149853785508106018564787140458587165768350143018847840661371060583295055600185059031740"
        "386698369796694993301139380463919242175430688496936048982929502368583755",
        "0."
        "02213435983999749088040606072701436212579363086495183327060157486170002544810918630175583386283034397310018118"
        "09957519245146115781496877328088402123991347355593551168167003461966850579164614448891791171428078588835744260"
        "62415931319905031345377305247124198345242221848293630112578508459623098934259229893301963120289071135120089672"
        "338617200639338087265986570094025605269870532431816151660553037324591448",
        "0."
        "02404589566203578515770662377856932950543269950417165906429674776176194691029507429183882698171279236828234955"
        "39051759968586459672801354175774888106515947766265622526867584638138207910315805797217822517056005708380441583"
        "57396828391251385978824608388341556751951593319015721256942139947235672567093309227673005475237474351604086627"
        "391812539914665025071874865132198040631867741985556198082915821590691115",
        "0."
        "02595734357424244836428547904034421154921442177233640890479169021044982558086884122972893790914113611665289447"
        "54769914714945245010358099562882470108614643020661542547364254604680243505715847804892130564280985606863769995"
        "62953811729945811217829999284678155635497607933780499844559793793320393174691097636750027421158473345884329284"
        "455326733063073401001936304522649050748641723222539485352644237494855455",
        "0."
        "02786869658851994837340013731772800760858742770166896433084496039323296265934708860449270625153048714880568350"
        "58831528822041777234043074653243834084187165792805158719497902045861718859817616990663010094101768016350039611"
        "67315448162116236938093263170474354430610732127054993766008385425707409224417795873645410443727472246508894027"
        "549288331903202127478347028519320691939639175445464091747341289465807076",
        "0."
        "02977994771711769214064161695942308897505915896467130739365457176349155359058255901528353353298601861402999585"
        "42787480391551770888394144504544095712671107207133742883636708046922893947708040511825104959003229152946134791"
        "46430103948686457060129295537542317247965142780968717375277053102667416124807987527429828758851341378395347636"
        "356414345553353015296944031211364374602764176767114282660874356057979248",
        "0."
        "03169108997265757234968007548831539092664261419258315028339932724609641378752993073240305448323210275610250474"
        "04838751800329369142967019031683971889264747515160555711385296692528872255726174898100171764266107573499374851"
        "05062771657304722076477636782048137141940828525026216230072442146056460947877309925103189247723289581298576409"
        "53691466395972638014259980360897599169526022683004620965496473543834477",
        "0."
        "03360211636815951269623302604906544623950481693175472231431690699171989413559977782675060918501864763374802360"
        "26625685533644552537419947015117524785061756714490298591935833323809242981643506270237972180985394412289864926"
        "01142199774579432202424360114528105854714450548265654769162069979862894518829365029262734944196495563243510942"
        "310738160350648115273816371164862001848102516957052031698646996790510953",
        "0."
        "03551301991706701171686466579169359170126622106906614298872651683203672861330045700640329960138592297328557312"
        "41476697176184865709868600085643096416579431727579124515065727834498305861638144775027203410108701192310305116"
        "64725149033496023356743601581035789746158436049009960920433265660001864258067191594425969638702851317416487965"
        "304378219676062220223886417078628342731900948906319081697480745936074075",
        "0."
        "03742379363327268506923016328909941054820146048508325058481589054569550176063473734802710692115534956480532122"
        "22828247090725822341858495644406700008475715613593246298773686202227758560685692785905828435500960966275101092"
        "10574429458414697641703261368397349100700647508781941466979105505468662952228018391181441110331804231754679360"
        "190526351574820397399161022517352576803713854137820941977691824804918229",
        "0."
        "03933443053114380617038441347727393691454078249067953255979519905208426335398124312840825908661959393894615829"
        "41754657926335844215923500114551981248467781944172810056202589826152272348717806793272892320728587512853079553"
        "84102986030326321993554199425677956531006546270705693578070953933490084008156062047268010604414954653769711129"
        "551190023978078265436680151306319349753427763894284339669614362603225399",
        "0."
        "04124492362554784509978077138923576064529252794948104409449088377792129014065050432251647263718480321413071443"
        "12794744044345131670885432021719221788741189679913017441868580545084734136471487442600574239310331779731191109"
        "21967581379650616945061418716237102199971097086754171168500651650526166023618723542873290120298640370217463634"
        "503988257867984189842393302366909916756244585593509804376197012137137735",
        "0."
        "04315526593187800567359162010550325021364842256850034799352917194217685500024708214705218927539412743238996642"
        "76684131276653664897092296029263845883610711262970405471806229893952535182591977420538104193724523725065343132"
        "64090033740095357809571640645325965973975968081307185286025492280541542290934505383760407808393490207181258819"
        "590768103829347539943429968533891105456889889207923129412409325200337396",
        "0."
        "04506545046607876059698931384201095697288926962984099661854147107645614534157634603714073755408708959823265734"
        "05418651083892582655114623077088559323082846108052090844134606145985700623540889311795879847020068475661624924"
        "14964136182928014974554852612762940578089297583097434972291633301329615187665009664697057933900728259220674217"
        "919826618275818024987757805509580781060051826778978395144370327934582031",
        "0."
        "04697547024467138460103306391634724027149630100803003888530052526798529225905129916603848616846213109692607792"
        "06112549663229653956732213245062135934152631896673937271249784541251041922360043030563483207060910187819908031"
        "64595039969574510002737990997634364247271320535459089400357647302806652831431190979518269432197656547265417669"
        "309719787317687585776029758282182901563328846367691507505917911626458378",
        "0."
        "04888531828477948547081470344934277987415714118827253901246150779059879616984405442070140074728810386335100859"
        "38343753360089524191612977876803559816725058844056452570946166834970404717219802416796169124837888440076494479"
        "69703512155758482444019770785766752697959554691538291379700303132353876869628124563105576278585509058450081192"
        "711918856522653293896204836307264696289474219755720645459588331890558889",
        "0."
        "05079498760415453287152397604443868847898854652227570259113516529507568483477506978208754021215531159992463221"
        "68787173632790384062037479686375739946881463292967550237291705059309350281073595300429098223692456090916967040"
        "70694133386183688825674952803613566914142157159664703170379754943610785780639205752343103591085978554489192416"
        "588288410803225066825839880971435465232206429722600557780654218330146221",
        "0."
        "05270447122120138487910204431372351921454183084429433900200615029500026180362977793066820271387562936891401261"
        "38401801741565983990969846058420009177093308938713659612428128606330221326634350788694332623710622005553335085"
        "65564704972551921154864927879748108180002977668648111714062992755985320189721615088748697314805428967770533095"
        "416911693326757965362169171309026356339280576158225848771071227224373815",
        "0."
        "05461376215500381212216030595761814768611374506398965060717916315739882081771507944926880218936299871925694703"
        "55415525248394971197218845368652407050174034090533016251526851516447613344098971998100935050975286508977292790"
        "62117617766845257388412635800174656504897022571125534403010151970450307624961920347280823962725005822339087173"
        "498538012712497715370388872960900453285934131578336748483622553313648565",
        "0."
        "05652285342535001944185033812422642040437262822947495473031646122402927979344912114894183015570585636429065529"
        "66960088653490586503962976679517456392663449939111112720760195224763152549209314694063810887403924363529971787"
        "77214659473302034620137440843681809428909274912969436139312159105442160243076856936138443854294531618433726198"
        "293972487505166088883354213979143973990964298454127970039847456893860203",
        "0."
        "05843173805275816497637986494243039655597709873498601130932141310480208079882403956546152160835512210202272546"
        "12202699672516198433948606410706219514337657633697616589168168808681882750324531371842116739340792772855939351"
        "59478757148621410070196500221526968060556586710920750728824112282461003224923995158937905479480579208549847478"
        "185757177039153501786271361921802927586114942206193581554801605680183774",
        "0."
        "06034040905850187657687905840671755037544989792286634902461253137367772496569289676345169003475021480739308606"
        "02321839627418934556308002825287060946343124978678631942529144550621275446719094245053675595036498904775701167"
        "67021509485710626043408265846213906257952113003324887350087083283630715857354116849013376841533857321740197047"
        "217435805280085872071354373524395263864933170034771001607559366437835689",
        "0."
        "06224885946463576546133123915706193746686049729742751789281333411875145041642253752249398319274836506892916659"
        "69433184976628447281196360778248899395966991394244099581633952977765674029786747119154090952068012290915918241"
        "18034413910654682971112744820893477373223133341441618370357576610552838101432388468114962860869260750080684897"
        "24098160672664550444107807861952850135669761489736449089327971794824585",
        "0."
        "06415708229402093701329214110827358506893318568172280658617313651296908656115100058608322882770447492213365936"
        "82084994285175609372677112875582758563258517355270475255491356028099539243462323935753545053415164088770347951"
        "44989051337120442048812961016500803766780090428411925756071299228254760633032932651170483895163866111455935100"
        "454818941073761804284777739005007991141161823471943803047351369535073521",
        "0."
        "06606507057035049863213234230316493277441147645258154898838614545430984417078463121990068754537566972606241127"
        "82101488337618870758893826317113197620667175188427872735431439698741770593860032625169412151682349972454207359"
        "13778365997498382320917159517052861653706668051150014889560865161606396037665048820655743861710636504450723955"
        "435275019348223982732095398949832565423361714391500479155224225613768011",
        "0."
        "06797281731817506454154824375449801542992858851651718382231326444687963568209311338426499328040848278019304768"
        "73703058923091067488755194865408790201429023623072376896846970637922258381117422417147898236012519982993312540"
        "97504567214769822096812914869886418586879378868131071702869283011709161582762527864014863950459121468893761825"
        "841337802563429112718615110803469902519051203360473993644451463303576859",
        "0."
        "06988031556292825746309809836256267170918370639812214696909812917947237945553998427031788938272567855131467803"
        "09025157821882038023624602140701923786663113697307559126706609703784082848764651923563403352772254577760915159"
        "34608751710356445501169982098020701963512215973413220903547301855847279762573955110834619967590588317288171580"
        "291576756417265600792610005176888567344924086299458709493921684370833814",
        "0."
        "07178755833095220706153105320773939112422621828807137340295968530357389407193799909693128341539738529630622848"
        "41287261252235682927601107630757396121741828401481935175403793028969383753577447548318855704822998029852785256"
        "92833941172622048860945698352794727105726197891701070706523197225463566498764869186174536278875440544967870368"
        "440256565084805804998877012238900798874720340885805165811704445925369809",
        "0."
        "07369453864952304506868897057861922170414313661538863465614770246556638808351254050794164760581857499175318127"
        "11774559759504639945373741523496609046081938327833818426551829439358931606743429630732087351487337553449900089"
        "55070929201231627937227422789029562631786758739801210895258148401153007301244579596320133604797765542622108017"
        "98434607194598511786777350540581826836696200671400628870250659962729555",
        "0."
        "07560124954687639699277293596304007783475912288726432487682674659729850704257079531594037895736964666654561692"
        "79300466771796467221875578604425060251105419682574060526796046818920865179516481122017670290446371423349377861"
        "45563391280677987040697732028896674786378870229133792190093646530752257521390201161387698590619925316803401938"
        "362974478273195688740273778224688121208296858072701246429755713258468481",
        "0."
        "07750768405223287031977884485736048308798866580915737599480523539069522794527382684233591697126224532246386169"
        "89879884914330927594156206857548134562479892871579096013767421416478866843804733794030673439776333476556837458"
        "71434202230624968375294472571053679501320680048739346844244553807193670436672857163839591129928936603341033670"
        "518982144557944158002407590669543043048232580344768659176122645763500513",
        "0."
        "07941383519582353911391928459278913150807428005691345661714886319007726058418647615016810176603269249958501957"
        "23000094771073423257318060035396457497209982600748940055032437157777881877545502864883169663206237074038469739"
        "34258796072434720381188302956748572794547906591019552569722211941807674118070825610462581312695693650893380241"
        "875873254675082431417454526920871842555422162216221640850141209989864308",
        "0."
        "08131969600891542492386209238973689981181951147511231088791689043624679770473070467372905608832478409692135372"
        "17910551025638125923751893468163489526216032488275289234339985975584783667126582356569246017749210950793565658"
        "67874041683517103417362062033545480747089630436317004907748679995334911923789802669273406449877710501792905734"
        "235548100216242648355048174292232350538531258791292074224222773259366265",
        "0."
        "08322525952383697390162947648382688257049509740972294821115665187141191592634769844331760632491209501384638614"
        "48480760193349830603239963645756222312841563713112098033838682976660271427764926047134514011163049519160373513"
        "15288808149328656282592946622481248077426878390562084748274992526750980236994304445617883874613002677387890383"
        "751048690275480465558930319669630406765794141303531112767626885032234711",
        "0."
        "08513051877400353004101543337101216212359033856529771289945157227404487085813240168529498972643275680825161819"
        "88094971170314287542241824637681893339926104117503242492837866476059645935565808414886861893743107033284906383"
        "78071341189999989736919850819640255203388192531225871093915262442913255553964348789674386732423763999398384843"
        "950222967487918049677831350991752153610543052586794779289758903475438463",
        "0."
        "08703546679394280444239338094358977387480738413770177780775585860655580609004531379334974366769766649578482854"
        "02475876273815815456209187951078777150862279321927561447800868565156412981955582044847281155194455147327555721"
        "78929839231921546119143469647706999890259163924570037168105911942268212237224359201159897493303064534985539474"
        "450028748960081579369980283792804593122976296597796047722827878891322393",
        "0."
        "08894009661932034051080045448189717964378771450498890477954943042290588204478205437582890610045687999231364014"
        "49342424181294006797068656443166644580619536848566073418116675764181633398433720412953227097970078716047404914"
        "53013916791024918954258557372755707588171502529270934617054742841996068375532958173787119651672031238405892943"
        "090742861150287144368470297356054911834742041692715934237148148936307154",
        "0."
        "09084440128696497499419978007502428517353424061697293830856612400231817615623334333379765277125022803359776734"
        "08464760942108132997230663449555424552468973029459083367564645821898293353150553185091716230723825736561729913"
        "07091055717376996812421994002305994837615827430425975713541786272473174908117299253875064746541808768776888139"
        "494200307162476704515967971265236163183394620211890252072718610942571965",
        "0."
        "09274837383489429476883724801361486954592004075766677188979226434736733592228398794408137035693921479951082255"
        "86389354861121903597017906627929257731868976712448319714504749520366189378337068990060484697912131299223027984"
        "62311426294239282200248625552430083292818594731518350634587677158329361662244008606299358410273467156168469937"
        "529868888478684257396004386633746334360279683178784117372066095688934486",
        "0."
        "09465200730234008927862485697316713821725813756576269941336416399395064198979833690322405942579887230845186693"
        "07808428784355038323663162451591540443505177273126549804552901635140218608020282519819547245802922478878511856"
        "39950862672925642859475325430465650514258094310141033116303195908372018392349011340787373492402788283020594141"
        "795669947097771918542864972570255253465754192708165241608041715996375567",
        "0."
        "09655529472977379853549858833033074225823562054271495313739665642376685099661084023094270272485976247900824483"
        "81091163463581955833463091026735332002926133029697729272026665530851355953058684355022920851738878978301188745"
        "08654885541434753025903539157323216634180575675730425948018662589483806840007690913531658799531110462605327968"
        "91917772727185993569684246844052518121013717183610828519193371796413317",
    }};

    T half_pi = static_cast<T>(
        "1."
        "57079632679489661923132169163975144209858469968755291048747229615390820314310449931401741267105853399107404325"
        "66411533235469223047752911158626797040642405587251420513509692605527798223114744774651909822144054878329667230"
        "6423782411689339158263560095457282428346173017430522716332410669680363012457064");

    max_err = 0;
    for (unsigned k = 0; k < near_one.size(); k++) {
        static const T euler_gamma = static_cast<T>(
            "5."
            "7721566490153286060651209008240243104215933593992359880576723488486772677766467093694706329174674951463144"
            "7249807082480960504014486542836224173997644923536253500333742937337737673942792595258247094916008735203948"
            "165670853233151776611528621199501507984793745085705740029921354786146694029604325421519e-1");
        T val = cos(half_pi - (euler_gamma + k) / 523);
        T e = relative_error(val, T(near_one[k]));
        unsigned err = e.template convert_to<unsigned>();
        if (err > max_err)
            max_err = err;
        val = cos(-half_pi + (euler_gamma + k) / 523);
        e = relative_error(val, T(near_one[k]));
        err = e.template convert_to<unsigned>();
        if (err > max_err)
            max_err = err;
    }
    std::cout << "Max error was: " << max_err << std::endl;
#if defined(BOOST_INTEL) && defined(TEST_FLOAT128)
    BOOST_TEST(max_err < 8000);
#else
    BOOST_TEST(max_err < 750);
#endif

    //
    // Test with some exact binary values as input - this tests our code
    // rather than the test data:
    //
    static const boost::array<boost::array<T, 2>, 8> exact_data = {
        {{{0.5, static_cast<T>("0."
                               "877582561890372716116281582603829651991645197109744052997610868315950763274213947405794"
                               "184084682258355478400593109053993")}},
         {{0.25, static_cast<T>("0."
                                "96891242171064478414459544949418919980413419028744283114812812428894256118452332726465"
                                "5202799685025510352709626116202617")}},
         {{0.75, static_cast<T>("0."
                                "73168886887382088631183875300008454384054127605077248250768322022075008250156949954096"
                                "7562610201174960122884908227300721")}},
         {{std::ldexp(1.0, -20), static_cast<T>("0."
                                                "9999999999995452526491135703469013368438582357746312643224146889053936"
                                                "5027135494672267164697779879113636143901797362388")}},
         {{2, static_cast<T>("-0."
                             "41614683654714238699756822950076218976600077107554489075514997378196493612407916907453177"
                             "7860169140367366791365215728559")}},
         {{5, static_cast<T>("0."
                             "28366218546322626446663917151355730833442259225221594493035906658615145676738270228617698"
                             "1668344573238827368717546699737")}},
         {{10, static_cast<T>("-0."
                              "8390715290764524522588639478240648345199301651331685468359537310487925868662707684009337"
                              "12760422138927451054405350243624")}},
         {{8.5, static_cast<T>("-0."
                               "602011902684823615348426522956998700296067763604355235396366061455725158767706195460253"
                               "51418378467287262574566665150299")}}}};
    max_err = 0;
    for (unsigned k = 0; k < exact_data.size(); k++) {
        T val = cos(exact_data[k][0]);
        T e = relative_error(val, exact_data[k][1]);
        unsigned err = e.template convert_to<unsigned>();
        if (err > max_err)
            max_err = err;
        val = cos(-exact_data[k][0]);
        e = relative_error(val, exact_data[k][1]);
        err = e.template convert_to<unsigned>();
        if (err > max_err)
            max_err = err;
    }
    std::cout << "Max error was: " << max_err << std::endl;
    BOOST_TEST(max_err < 20);

    BOOST_TEST(cos(T(0)) == 1);
#if defined(BOOST_INTEL) && defined(TEST_FLOAT128)
    BOOST_TEST(fabs(cos(half_pi)) < 4 * std::numeric_limits<T>::epsilon());
#else
    BOOST_TEST(fabs(cos(half_pi)) < std::numeric_limits<T>::epsilon());
#endif

#include "sincos.ipp"
    max_err = 0;
    for (unsigned k = 0; k < sincos.size(); k++) {
        T val = cos(sincos[k][0]);
        T e = relative_error(val, sincos[k][2]);
        unsigned err = e.template convert_to<unsigned>();
        if (err > max_err)
            max_err = err;
    }
    std::cout << "Max error was: " << max_err << std::endl;
    BOOST_TEST(max_err < 20);

    if (has_poor_large_value_support<T>::value) {
        T bug_value = 12 / std::numeric_limits<T>::epsilon();
        for (unsigned i = 0; i < 20; ++i, bug_value *= 1.1) {
            BOOST_TEST(cos(bug_value) == 1);
        }
    }
}

int main() {
#ifdef TEST_BACKEND
    test<
        nil::crypto3::multiprecision::number<nil::crypto3::multiprecision::concepts::number_backend_float_architype>>();
#endif
#ifdef TEST_MPF_50
    test<nil::crypto3::multiprecision::mpf_float_50>();
    test<nil::crypto3::multiprecision::mpf_float_100>();
#endif
#ifdef TEST_MPFR_50
    test<nil::crypto3::multiprecision::mpfr_float_50>();
    test<nil::crypto3::multiprecision::mpfr_float_100>();
#endif
#ifdef TEST_MPFI_50
    test<nil::crypto3::multiprecision::mpfi_float_50>();
    test<nil::crypto3::multiprecision::mpfi_float_100>();
#endif
#ifdef TEST_CPP_DEC_FLOAT
    test<nil::crypto3::multiprecision::cpp_dec_float_50>();
    test<nil::crypto3::multiprecision::cpp_dec_float_100>();
#ifndef SLOW_COMPLER
    // Some "peculiar" digit counts which stress our code:
    test<nil::crypto3::multiprecision::number<nil::crypto3::multiprecision::cpp_dec_float<65>>>();
    test<nil::crypto3::multiprecision::number<nil::crypto3::multiprecision::cpp_dec_float<64>>>();
    test<nil::crypto3::multiprecision::number<nil::crypto3::multiprecision::cpp_dec_float<63>>>();
    test<nil::crypto3::multiprecision::number<nil::crypto3::multiprecision::cpp_dec_float<62>>>();
    test<nil::crypto3::multiprecision::number<nil::crypto3::multiprecision::cpp_dec_float<61, long long>>>();
    test<nil::crypto3::multiprecision::number<nil::crypto3::multiprecision::cpp_dec_float<60, long long>>>();
    test<nil::crypto3::multiprecision::number<
        nil::crypto3::multiprecision::cpp_dec_float<59, long long, std::allocator<char>>>>();
    test<nil::crypto3::multiprecision::number<
        nil::crypto3::multiprecision::cpp_dec_float<58, long long, std::allocator<char>>>>();
#endif
#endif
#ifdef TEST_FLOAT128
    test<nil::crypto3::multiprecision::float128>();
#endif
#ifdef TEST_CPP_BIN_FLOAT
    test<nil::crypto3::multiprecision::cpp_bin_float_50>();
    test<nil::crypto3::multiprecision::number<nil::crypto3::multiprecision::cpp_bin_float<
        35, nil::crypto3::multiprecision::digit_base_10, std::allocator<char>, boost::long_long_type>>>();
#endif
    return boost::report_errors();
}
